﻿using System;

namespace Zive.Color {

    public class BradfordTransform {

        private static readonly Matrix _ConeResponseTransform = new[ , ] {
            {  0.8951000d,  0.2664000d, -0.1614000d },
            { -0.7502000d,  1.7135000d,  0.0367000d },
            {  0.0389000d, -0.0685000d,  1.0296000d }
        };
        private static readonly Matrix _InverseConeResponseTransform = new[ , ] {
            {  0.9869929d, -0.1470543d,  0.1599627d },
            {  0.4323053d,  0.5183603d,  0.0492912d },
            { -0.0085287d,  0.0400428d,  0.9684867d }
        };

        private readonly Illuminants _sourceIlluminant;
        public Illuminants SourceIlluminant { get { return _sourceIlluminant; } }

        private readonly Illuminants _destinationIlluminant;
        public Illuminants DestinationIlluminant { get { return _destinationIlluminant; } }

        private readonly Matrix _adaptationTransform;

        private BradfordTransform( ) { }

        internal BradfordTransform( Illuminants source, Illuminants destination ) {
            _sourceIlluminant = source;

            _destinationIlluminant = destination;

            var sourceConeResponse = _ConeResponseTransform.Multiply( _sourceIlluminant.GetReferenceWhite( ) );
            var destinationConeResponse = _ConeResponseTransform.Multiply( _destinationIlluminant.GetReferenceWhite( ) );

            _adaptationTransform = _InverseConeResponseTransform.Multiply( new [ , ] {
                { destinationConeResponse[ 0, 0 ] / sourceConeResponse[ 0, 0 ], 0d, 0d },
                { 0d, destinationConeResponse[ 1, 0 ] / sourceConeResponse[ 1, 0 ], 0d },
                { 0d, 0d, destinationConeResponse[ 2, 0 ] / sourceConeResponse[ 2, 0 ] }
            } ).Multiply( _ConeResponseTransform );
        }

        public XyzColor Transform( XyzColor sourceColor ) {
            if ( sourceColor.Illuminant != _sourceIlluminant ) {
                throw new ArgumentException( "Parameter's illuminant is incompatible with the transform.", "sourceColor" );
            }

            var destinationColorMatrix = _adaptationTransform.Multiply( new[ , ] {
                { sourceColor.X },
                { sourceColor.Y },
                { sourceColor.Z }
            } );
            var result = new XyzColor {
                Illuminant = _destinationIlluminant,
                X = destinationColorMatrix[ 0, 0 ],
                Y = destinationColorMatrix[ 1, 0 ],
                Z = destinationColorMatrix[ 2, 0 ]
            };
            return result;
        }

    }

}
